#include<iostream>
#include<cstdio>
#include<unordered_map>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
 using namespace std;
#define COMMAND_SIZE 1024
#define FORMAT "[%s@%s  %s]"
#define SLASH "/"
char*  g_argv[128];
int g_argc=0;
//2.huanjingbianlinag
#define MAX_ENVS 100
char * g_env[MAX_ENVS];
int g_envs=0;
//3.别名映射表
std::unordered_map<std::string,std::string> alias_list;
//for test 
char cwd[1024];
char cwdenv[1024];
//
int lastcode=0;
//重定向标记
int  redirect_type=0;//0-无重定向，1-输出重定向，2-输入重定向，3-追加重定向
char redirect_file[1024]={0};
const char* GetUserName()
{
  const char*name=getenv("USER");
  return name==NULL?"None":name;

}
 const char* GetHostName()
 {
  const char*host=getenv("HOSTNAME");
   return host ==NULL?"None":host;
    
 }
const char*GetPwd()
{
  const char *pwd=getcwd(cwd,sizeof(cwd));
  if(pwd!=NULL){
    snprintf(cwdenv,sizeof(cwdenv),"PWD=%s",cwd);
    putenv(cwdenv);
  }
  return pwd==NULL?"None":pwd;

}
const char *GetHome()
{
  const char *home=getenv("HOME");
  return  home==NULL?"":home;
}
void InitEnv(){
  extern char** envirion;
  memset(g_env,0,sizeof(g_env));
  g_envs=0;
  for(int i=0;environ[i];i++){
    g_env[i]=(char*)malloc(strlen(environ[i]+1));
    strcpy(g_env[i],environ[i]);
    g_envs++;
  }
  g_env[g_envs++]=(char*)"HAHA=for_test";
  g_env[g_envs]=NULL;
  //2.导成环境变量
  for(int i=0;g_env[i];i++)
  {
   putenv(g_env[i]);
  }
  environ=g_env;
}
bool cd(){
  if(g_argc==1)
  {
    std::string home=GetHome();
    if(home.empty()) return true;
    chdir(home.c_str());
  
  }
  else{
    std::string where=g_argv[1];
    if(where=="-"){

    }
    else if(where=="~")
    {

    }
    else{
      chdir(where.c_str());
    }
  }
    
  return true;
}
void Echo(){
  for (int i = 1; i < g_argc; i++) {
    string arg=g_argv[i];
    if(arg.size()>=2&&arg[0]=='"'&&arg[arg.size()-1]=='"')
    {
      arg=arg.substr(1,arg.size()-2);
    }
    cout << arg;
    if (i != g_argc - 1) cout << " ";  // 参数间添加空格
  }
  cout << endl;  // 输出换行
}
string DirName(const char *pwd)
{
  string dir=pwd;
  if(dir==SLASH) return SLASH;
  auto pos=dir.rfind(SLASH);
  if(pos==string::npos) return "BUG?";
  return dir.substr(pos+1);
}

void MakeCommandline(char cmd_prompt[],int size)
{
  snprintf(cmd_prompt,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPwd()).c_str());
}
void Printcmd(){
  char prompt[COMMAND_SIZE];
  MakeCommandline(prompt,sizeof(prompt));
  printf("%s",prompt);
  fflush(stdout);

 }
bool GetComandLine(char*out,int size){                                                                                
 char*c= fgets(out,size,stdin);                                                                 
 if(c==NULL) return false;                                                                                         
 out[strlen(out)-1]=0;
 if(strlen(out)==0) return false;
 return true;
}
//3.命令行分析
bool CommandParse(char *commandline)
{
#define SEP " "
  g_argc=0;
  redirect_type=0;
  memset(redirect_file,0,sizeof(redirect_file));
  char* token=strtok(commandline,SEP);
  while(token!=NULL)
  {
    if(strcmp(token,">")==0)
    {
      redirect_type=1;
      token=strtok(nullptr,SEP);
      if(token!=NULL) strcpy(redirect_file,token);
      else{
        fprintf(stderr,"缺少重定向文件");
        return false;
      }
     break;
    }
    else if(strcmp(token,">>")==0)
    {
       redirect_type=3;
        token=strtok(nullptr,SEP);                                                                                     
        if(token!=NULL) strcpy(redirect_file,token);                                                                   
        else{                                                                                                          
         fprintf(stderr,"缺少重定向文件");                                                                            
          return false;                                                                                                
       }  
      break;
    }
   else if(strcmp(token,"<")==0)
     {
      redirect_type=2;
        token=strtok(nullptr,SEP);                                                                                     
         if(token!=NULL) strcpy(redirect_file,token);                                                     
         else{                                                                                                          
         fprintf(stderr,"缺少重定向文件");                                                                          
         return false;                                                                                                
       }  
      break;
    }
    else{
     g_argv[g_argc++]=token;
    token=strtok(nullptr,SEP);
    }

  }
  g_argv[g_argc]=NULL;
  return g_argc>0?true:false;
}
//打印环境变量
void PrintArgv()
{
  for(int i=0;g_argv[i];i++)
  {
    printf("argv[%d]->%s\n",i,g_argv[i]);

  }
  printf("argc:%d\n",g_argc);

}
//检测并执行内健命令
bool checkAndExectBuiltin()
{
  string cmd =g_argv[0];
  int sto=-1;
  int sti=-1;
  if(redirect_type!=0)
  {
    int fd;
    mode_t mode = 0664;
    switch (redirect_type) {
      case 1:  // 输出重定向（覆盖）
        fd = open(redirect_file, O_CREAT | O_WRONLY | O_TRUNC, mode);
        break;
      case 3:  // 追加重定向
        fd = open(redirect_file, O_CREAT | O_WRONLY | O_APPEND, mode);
        break;
      case 2:  // 输入重定向
        fd = open(redirect_file, O_RDONLY);
        break;
      default:
        fd = -1;
    }
     if(fd==-1)
     {
      perror("文件打开失败");
      return true;
     }
     if(redirect_type==1||redirect_type==3)
     {
       sto=dup(STDOUT_FILENO);
       dup2(fd,STDOUT_FILENO);
     }
     else if(redirect_type==2)
     {
       sti=dup(STDIN_FILENO);
       dup2(fd,STDIN_FILENO);
     }
     close(fd);
  }
    bool is_bui=true;
  if(cmd=="cd")
  {
    cd();
    return true;
  }
  else if(cmd=="echo")
  {
    Echo();
    return true;
  }
  else if(cmd=="export")
  {

  }
  else if(cmd=="alias")
  {

  }
  else{
    is_bui=false;
  }
  if(sto!=-1)
  {
    dup2(sto,STDOUT_FILENO);
    close(sto);
  }
  if(sti!=-1)
  {
    dup2(sti,STDIN_FILENO);
    close(sti);
  }
  return is_bui;
}

int Execute()
{
  pid_t id=fork();
  if(id==0)
  {
    if(redirect_type!=0)
    {
      int fd;
      mode_t mode=0664;
      switch(redirect_type)
      {
      case 1:
        fd=open(redirect_file,O_CREAT|O_WRONLY|O_TRUNC,mode);
        break;
      case 2:
        fd=open(redirect_file,O_RDONLY);
        break;
      case 3:
        fd=open(redirect_file,O_CREAT|O_WRONLY|O_APPEND,mode);
        break;
      default:
        fd=-1;
      }
      if(fd==-1)
      {
        perror("文件打开失败");
        exit(1);
      }
      if(redirect_type==1||redirect_type==3)
      {
        dup2(fd,1);
      }
      else if(redirect_type==2)
      {
        dup2(fd,0);
      }
      close(fd);
    }
    execvp(g_argv[0],g_argv);
    exit(1);
  }
  int status=0;
  pid_t rid=waitpid(id,&status,0);
  if(rid>0)
  {
    lastcode=WEXITSTATUS(status);
  }
  return 0;
}

int main()
{
  InitEnv();
  while(true)
  {
  //1.打印命令行提示符
  Printcmd();
  //2.获取命令
   char commandline[COMMAND_SIZE];
   if(! GetComandLine(commandline,sizeof(commandline)))
     continue;
  // cout<<"echo "<<command<<endl;
  //3.命令行分析
   if(!CommandParse(commandline))
     continue;
  //4.检测并处理内键命令
   if(checkAndExectBuiltin())
     continue;
   //5.执行命令；
   Execute();
   }
 return 0;
}
